<template>
  <div @click="handleOutsideClick">
    <div class="top">
      <div class="top-op">
        <div class="btn">
          <el-upload
    :show-file-list="false"
    :with-credentials="true"
    :multiple="true"
    :http-request="addFile"
    :accept="fileAccept"
    webkitdirectory
>
    <el-button type="primary" round style="padding: 8px 24px">
        <span class="iconfont icon-upload" ></span>
        上传
    </el-button>
</el-upload>

        </div>
        <el-button type="primary" @click="newFolder" text round bg>
          <span class="iconfont icon-folder-add"></span>
          新建文件夹
        </el-button>
        <el-button
          @click="delFileBatch"
          type="danger"
          :disabled="selectedFileIds.length === 0"
        >
          <span class="iconfont icon-del"></span>
          批量删除  
        </el-button>
        <div class="search-panel">
          <el-input
            clearable
            placeholder="输入文件名搜索"
            v-model="searchQuery"
            @keyup.enter="searchFiles"
          >
            <template #suffix>
              <i class="iconfont icon-search" @click="searchFiles"></i>
            </template>
          </el-input>
        </div>
      </div>
      <Navigation ref="navigationRef" @navChange="navigateFolder"></Navigation>
    </div>

    <div class="breadcrumb">
      <span v-for="(item, index) in breadcrumb" :key="item.fileId">
        <a @click="navigateToFolder(item.fileId)">{{ item.fileName }}</a>
        <span v-if="index < breadcrumb.length - 1"> / </span>
      </span>
    </div>

    <div class="file-list" v-if="filteredFiles.length > 0">
      <el-table
        ref="tableRef"
        :data=filteredFiles
        style="width: 100%"
        stripe
        @selection-change="onRowSelected"
      >
        <el-table-column
          type="selection"
          width="50"
        ></el-table-column>
        <el-table-column label="文件名" prop="fileName" width="150" align="center">
  <template #default="{ row }">
    <div class="file-item" @click.stop="handleFileClick(row)">
      <icon :fileType="row.fileType"></icon> <!-- 显示后缀名（大写）对应的图标 -->
      <span class="file-name" :title="row.fileName" v-if="currentEditingFile !== row">{{ row.fileName }}</span>
      <el-input v-if="currentEditingFile === row"
                 v-model="currentEditingName"
                 class="editing-input"
                 @keyup.enter="updateFileName(row.fileId)"
                 @click.stop
                 placeholder="输入新文件名">
      </el-input>
    </div>
  </template>
</el-table-column>


        <el-table-column
          label=" "
          width="400"
          align="center"
        >
          <template #default="{ row }">
            <div class="file-item" >
              <div class="edit-panel">
                <span class="iconfont icon-share1" @click.stop="share(row)"></span>
                <span class="iconfont icon-edit" @click.stop="renameFile(row)"></span>
                <span class="iconfont icon-download" @click.stop="downloadFile(row)"></span>
                <span class="iconfont icon-del" @click.stop="deleteFile(row)"></span>
              </div>
            </div>
          </template>
        </el-table-column>

        //文件类型
        <el-table-column
          label="类型"
          prop="fileType"
          width="200"
          align="center"
        >
      </el-table-column>

        <el-table-column
          label="时间"
          prop="uploadTime"
          width="200"
          align="center"
        >
          <template #default="{ row }">
            <span>{{ row.uploadTime }}</span>
          </template>
        </el-table-column>

        <el-table-column
          label="大小"
          prop="fileSize"
          width="auto"
          align="center"
        >
          <template #default="{ row }">
            <span v-if="!row.isFolder">{{ formatFileSize(row.fileSize) }}</span>
          </template>
        </el-table-column>
      </el-table>
    </div>

    <div class="no-data" v-else>
      <div class="no-data-inner">
        <Icon iconName="no_data" :width="120" fit="fill"></Icon>
        <div class="tips">当前目录为空，上传你的第一个文件吧</div>
      </div>
    </div>
  </div>
  <FileShare ref="shareRef"></FileShare>
</template>

<script setup>
import { ref, onMounted, inject, watch,computed } from "vue";
import FileShare from "./ShareFile.vue";
import http from "@/utils/http";
import {useRoute } from "vue-router";
import { ElMessage ,ElLoading} from 'element-plus'
import eventBus from "@/js/eventBus"
// 获取路由和用户ID
const route = useRoute();
const userId = inject('userID');

// 文件类型映射


// 当前分类
const category = ref("");

// 当前目录和面包屑
const currentFolderId = ref(0);
const breadcrumb = ref([{ fileName: "根目录", fileId: 0 }]);

// 文件列表和筛选条件
const files = ref([]);
const filteredFiles = ref([]);
const searchQuery = ref("");
const selectedFileIds = ref([]);

// 查询参数
const querParams = ref({
  userId: "",
  searchQuery: "",
  fileType: "",
});
const fileTypeMap = {
  文件夹: { desc: "目录", icon: "folder" },
  MP4文件: { desc: "视频", icon: "video" },
  MP3文件: { desc: "音频", icon: "music" },
  JPG文件: { desc: "图片", icon: "image" },
  PNG文件: { desc: "图片", icon: "image" },
  EXE文件: { desc: "exe", icon: "exe" },
  DOC文件: { desc: "doc", icon: "word" },
  EXCEL文件: { desc: "excel", icon: "excel" },
  TXT文件: { desc: "纯文本", icon: "txt" },
  CODE文件: { desc: "程序", icon: "code" },
  ZIP文件: { desc: "压缩包", icon: "zip" },
  其他文件: { desc: "其他文件", icon: "others" },
};
// 加载目录内容
const loadFolderContents = (folderId) => {
  querParams.value.userId = userId;
  querParams.value.folderId = folderId;
  querParams.value.fileType = "";

  http
    .post("/files/searchVisibleFilesById", querParams.value)
    .then((data) => {
      // 获取文件列表
      files.value = data.data.map(file => {
        const originalFileType = file.fileType; // 保存原始的文件类型（大写后缀名）
        // 检查 fileType 是否在 fileTypeMap 中
        const fileTypeInfo = fileTypeMap[originalFileType];
        console.log(file)
        return {
          ...file,
          fileType: originalFileType, // 保持文件类型为其后缀名大写
          fileTypeDesc: fileTypeInfo ? fileTypeInfo.desc : fileTypeMap['其他文件'].desc, // 如果不在映射中，使用“其他文件”的描述
          icon: fileTypeInfo ? fileTypeInfo.icon : fileTypeMap['其他文件'].icon, // 如果不在映射中，使用“其他文件”的图标
        };
      });

      // 排序：文件夹优先显示
      files.value.sort((a, b) => {
        if (a.isFolder && !b.isFolder) {
          return -1; // 文件夹在前
        } else if (!a.isFolder && b.isFolder) {
          return 1; // 文件在后
        } else {
          return a.fileName.localeCompare(b.fileName); // 按文件名排序
        }
      });

      // 处理分类显示
      if (category.value === "all") {
        filteredFiles.value = files.value; // 如果分类为 "all"，显示所有文件
      } else {
        searchFilesByCategory(); // 否则根据类型进行过滤
      }
    })
    .catch((err) => {
      console.log(err);
    });
};




// 按类型查询文件
const searchFilesByCategory = async () => {
     const categoryMap = {
       video: "MP4文件",
       music: 'MP3文件',
       image: 'G文件',
       doc: 'TXT文件',
       others: '其他文件',
     };

     const fileType = categoryMap[category.value];

     if (fileType !== undefined) {
       querParams.value.fileType = fileType;
       querParams.value.folderId = ""
       console.log('----------',querParams.value)
       await http
        .post("/files/searchVisibleFilesById", querParams.value)
        .then((data) => {
           filteredFiles.value = data.data;
        })
        .catch((err) => {
           console.log(err);
        });
     }
   };
   


// 监听 category 的变化
watch(
  () => route.params.category,
  (newCategory) => {
    category.value = newCategory || "all";
    loadFolderContents(currentFolderId.value); // 更新文件列表
  },
  { immediate: true }
);

// 处理文件点击
const handleFileClick = (file) => {
  if (file.isFolder) {
    currentFolderId.value = file.fileId;
    breadcrumb.value.push({ fileName: file.fileName, fileId: file.fileId });
    loadFolderContents( file.fileId);

    
  }
};

// 面包屑导航跳转
const navigateToFolder = (folderId) => {
  const index = breadcrumb.value.findIndex((item) => item.fileId === folderId);
  breadcrumb.value = breadcrumb.value.slice(0, index + 1);
  currentFolderId.value = folderId;
  loadFolderContents(folderId);
};

onMounted(() => {
  loadFolderContents(currentFolderId.value);
});

// 搜索文件
const searchFiles = async () => {
  if (searchQuery.value === "") { return;}
  querParams.value.searchQuery = searchQuery.value;
  loadFolderContents();
  querParams.value.searchQuery = "";
};

// 格式化文件大小
const formatFileSize = (size) => {
  if(size > 1024*1024){
    size = (size/1024/1024).toFixed(2) + 'MB'
        }else if(size ==0 || size == null){
          size = ' '
        }
        else{
          size = (size/1024).toFixed(2) + 'KB'
        }
        return size;
};

// 多选
const onRowSelected = (rows) => {
  console.log(rows);
  selectedFileIds.value = rows.map((row) => row.fileId);
};


const getCurrentFolderId = () => {
    // 根据 breadcrumb 的值返回当前文件夹的 ID
    if (breadcrumb.value.length > 1) { 
        return breadcrumb.value[breadcrumb.value.length - 1].fileId; // 返回最后一个项的 fileId
    }
    return 0; // 如果是根目录返回 0
};

const getCurrentPath = () => {
    // 如果 breadcrumb.value 只有根目录元素，返回空字符串
    if (breadcrumb.value.length === 1 && breadcrumb.value[0].fileName === '/') {
        return ''; // 返回空字符串，不显示根目录
    }

    // 返回从第二个元素开始的路径
    return breadcrumb.value
        .slice(1) // 从第二个元素开始，去掉根目录
        .map(item => item.fileName)
        .join('/'); // 合并为字符串
};






// 上传文件
const addFile = (file) => {
    const currentPath = getCurrentPath(); 
    const { file: uploadedFile } = file; 
    const fileName = uploadedFile.name;
    const fileSize = uploadedFile.size; 
    const fileType = uploadedFile.type; 
    const filePath = `${currentPath}/${fileName}`; 

    const files = {
        userId: userId,
        fileName: fileName,
        fileSize: fileSize,
        fileType: fileType,
        filePath: filePath,
        uploadTime: new Date(Date.now() + 28800000).toISOString().slice(0, 19).replace('T', ' '),
        parentId: currentPath === '' ? 0 : getCurrentFolderId()
    };

    const formData = new FormData();
    formData.append('file', uploadedFile); 
    formData.append('files', new Blob([JSON.stringify(files)], { type: 'application/json' }));

    let lastLoaded = 0;
    let startTime = Date.now();

    http.post('/files/uploadFile', formData, {
        headers: {},
        onUploadProgress: (progressEvent) => {
            if (progressEvent.lengthComputable) {
                const loaded = progressEvent.loaded;
                const total = progressEvent.total;
                const progress = Math.floor((loaded / total) * 100);

                // 计算上传速度并转换为 MB/s
                const elapsedTime = (Date.now() - startTime) / 1000; // 时间差，单位秒
                const uploadSpeedKB = (loaded - lastLoaded) / elapsedTime / 1024; // KB/s
                const uploadSpeedMB = uploadSpeedKB / 1024; // MB/s

                // 更新上次上传大小和时间
                lastLoaded = loaded;
                startTime = Date.now();

                // 发送上传进度数据，包括速度
                eventBus.emit("uploadProgress", { 
                    fileName, 
                    progress, 
                    uploadSize: loaded, 
                    totalSize: total, 
                    uploadSpeed: uploadSpeedMB.toFixed(2) // 保留两位小数
                });
            }
        }
    })
    .then((data) => {
        ElMessage.success(data.msg);
        eventBus.emit("uploadCompleted", { fileName }); 
        loadFolderContents(currentFolderId.value); 
    })
    .catch((data) => {
      ElMessage.error(data.msg);
        eventBus.emit("uploadFailed", { fileName, data: data.msg });
    });
};





// 删除文件
const deleteFile = async (row) => {
  const fileId = row.fileId;  
  await http.get('/files/fileRecycle', {
    params: {
      fileIds: fileId,
    },
  })
  ElMessage.success('文件删除成功')
  loadFolderContents(currentFolderId.value);
}


//将文件放到回收站
const delFileBatch = async () => {
  console.log(selectedFileIds.value);

  const fileIds = selectedFileIds.value;
  await http.get(
    '/files/fileRecycle',
    {
      params: {
        fileIds: fileIds.join(','),
      },
    }
  )
  ElMessage.error('文件删除成功')
  loadFolderContents(currentFolderId.value);
};


// 重命名文件
const currentEditingFile = ref(null);
const currentEditingName = ref("");
const renameFile = (file) => {
  currentEditingFile.value = file; // 保存当前正在编辑的文件
  currentEditingName.value = file.fileName; // 设置输入框的初始值
};
const updateFileName = async (fileId) => {
  // 检查新文件名是否为空
  if (!currentEditingName.value) {
    ElMessage.warning("文件名不能为空");
    return;
  }

  // 获取当前文件的信息
  const currentFile = filteredFiles.value.find(file => file.fileId === fileId);

  // 如果新文件名与原文件名相同，取消编辑
  if (currentEditingName.value === currentFile.fileName) {
    currentEditingFile.value = null; // 取消编辑状态
    return; // 不进行更新
  }

  // 构建更新文件名的请求数据
  const updatedFileData = {
    fileId: fileId,
    filePath: currentFile.filePath,
    userId: userId,
    newFileName: currentEditingName.value,
    FileName: currentFile.fileName,
    newFilePath: `${getCurrentPath()}/${currentEditingName.value}`,
  };
  console.log(updatedFileData)
  try {
    const data= await http.post('/files/reName', updatedFileData);
    ElMessage.success(data.msg);
    loadFolderContents(currentFolderId.value); // 刷新文件列表
  } catch (error) {
    console.error("重命名文件失败", error);
    ElMessage.error("重命名文件失败");
  } finally {
    currentEditingFile.value = null; // 结束编辑
  }
};

const handleOutsideClick = (event) => {
  // 检查当前是否有正在编辑的文件
  if (currentEditingFile.value) {
    // 如果点击的目标既不是输入框也不是文件项，取消编辑状态
    if (!event.target.closest('.file-item') && !event.target.closest('.el-input')) {
      currentEditingFile.value = null; // 取消编辑状态
    }
  }
};


// 新建文件夹
const newFolder = async () => {
    const currentPath = getCurrentPath(); // 获取当前路径
    const folderName = "新建文件夹";
    const files = {
        userId: userId,
        fileName: folderName,
        fileSize: 0,
        fileType: '文件夹',
        filePath: `${currentPath}/${folderName}`,
        uploadTime: new Date(Date.now() + 28800000).toISOString().slice(0, 19).replace('T', ' '),
        parentId: currentPath === '' ? 0 : getCurrentFolderId(), // 获取父 ID
        isFolder: true
    };
        const data = await http.post('/files/createFolder', files);
        ElMessage.success(data.msg);
        loadFolderContents(currentFolderId.value); 
        renameFile(files); 
};

//下载文件
// 下载文件
const downloadFile = (file) => {
  if (file.isFolder) {
    downloadFolder(file);
  } else {
    downloadAFile(file)
  }
};
const downloadFolder = (file) => {
  // 显示“下载中”的弹窗
  // 创建一个 AbortController 实例，用于取消请求
  const controller = new AbortController();
  const signal = controller.signal;

  // 显示“下载中”的弹窗，并添加取消按钮
  const loading = ElLoading.service({
    text: '文件下载，请稍候...', // 弹窗内容
    spinner: 'el-icon-loading',    // 自定义加载样式
    background: 'rgba(0, 0, 0, 0.7)',
    customClass: 'custom-loading-class', // 自定义样式类
    closeOnClickModal: false, // 点击遮罩不关闭
  });

  // 延迟插入取消按钮
  setTimeout(() => {
    const loadingElement = document.querySelector('.custom-loading-class .el-loading-spinner');
    if (loadingElement) {
      // 创建一个容器，包含下载进度和取消按钮
      const actionContainer = document.createElement('div');
      actionContainer.className = 'action-container';

      // 创建取消按钮
      const cancelButton = document.createElement('button');
      cancelButton.textContent = '取消下载';
      cancelButton.className = 'cancel-button1'; // 样式类名，可自行定义
      cancelButton.onclick = () => {
        controller.abort(); // 取消请求
        loading.close(); // 关闭加载框
        ElMessage.warning('下载已取消');
      };

      // 添加按钮到容器中
      actionContainer.appendChild(cancelButton);

      // 插入到弹窗中
      loadingElement.appendChild(actionContainer);
    }
  }, 100);
  http({
    method: 'get',
    url: '/files/getTaskId', // 包含文件或文件夹信息     // 只请求任务ID
    timeout: 600000 ,// 设置较长的超时时间
    signal, // 将 signal 传入请求
  }).then(response => {
    const taskId = response.msg; // 获取任务ID
    let downloadInProgress = false;
    file.taskId = taskId;
    http({
      method: 'post',
      url: '/files/downLoadFile',
      data: file,  // 包含文件或文件夹信息
      responseType: 'blob' , // 获取文件流
      signal, // 将 signal 传入请求
    }).then(fileResponse => {
      const blob = fileResponse;
      const downloadUrl = URL.createObjectURL(blob);
      const link = document.createElement('a');
      link.href = downloadUrl;
      link.download = file.fileName + ".zip" || 'downloaded_file.zip';  // 设置文件名
      link.click();  // 触发下载
      URL.revokeObjectURL(downloadUrl);  // 释放内存
      ElMessage.success('文件下载成功！');
    }).catch(error => {
      console.error('下载文件失败：', error);
      ElMessage.error('文件下载失败！');
    });
    // 开始轮询任务进度
    const checkProgressInterval = setInterval(() => {
      http({
        method: 'post',
        url: '/files/download-progress',
        data: "taskId=" + taskId,
        signal,
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded'
        }
      }).then(Response => {
        const progress = Response.data;
        console.log('下载进度：', progress + '%');
        loading.setText(`下载中... ${progress}%`);

        // 当进度达到100%时
        if (progress >= 100 && !downloadInProgress) {
          clearInterval(checkProgressInterval); // 停止进度查询
          loading.close();  // 关闭加载框
          downloadInProgress = true;  // 标记下载开始
        }
      }).catch(error => {
        console.error('进度查询失败：', error);
      });
    }, 3000);  // 每1秒查询一次下载进度
  }).catch(error => {
    console.error('下载任务创建失败：', error);
    ElMessage.error('任务创建失败！');
  });
}
const downloadAFile = (file) => {
  // 创建一个 AbortController 实例，用于取消请求
  const controller = new AbortController();
  const signal = controller.signal;

  // 显示“下载中”的弹窗，并添加取消按钮
  const loading = ElLoading.service({
    text: '文件下载，请稍候...', // 弹窗内容
    spinner: 'el-icon-loading',    // 自定义加载样式
    background: 'rgba(0, 0, 0, 0.7)',
    customClass: 'custom-loading-class', // 自定义样式类
    closeOnClickModal: false, // 点击遮罩不关闭
  });

  // 延迟插入取消按钮
  setTimeout(() => {
    const loadingElement = document.querySelector('.custom-loading-class .el-loading-spinner');
    if (loadingElement) {
      // 创建一个容器，包含下载进度和取消按钮
      const actionContainer = document.createElement('div');
      actionContainer.className = 'action-container';

      // 创建取消按钮
      const cancelButton = document.createElement('button');
      cancelButton.textContent = '取消下载';
      cancelButton.className = 'cancel-button1'; // 样式类名，可自行定义
      cancelButton.onclick = () => {
        controller.abort(); // 取消请求
        loading.close(); // 关闭加载框
        ElMessage.warning('下载已取消');
      };

      // 添加按钮到容器中
      actionContainer.appendChild(cancelButton);

      // 插入到弹窗中
      loadingElement.appendChild(actionContainer);
    }
  }, 100);

  http({
    method: 'post',
    url: '/files/downLoadFile',
    data: file,
    responseType: 'blob',
    timeout: 600000, // 设置响应超时
    signal, // 将 signal 传入请求
    onDownloadProgress: (progressEvent) => {
      // 计算下载进度
      if (progressEvent.lengthComputable) {
        const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
        console.log('下载进度：', percentCompleted + '%');
        loading.setText(`下载中... ${percentCompleted}%`);
      }
    }
  })
    .then(response => {
      if (response) {
        const blob = response;
        const downloadUrl = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = downloadUrl;

        // 设置下载的文件名   
        link.download = file.fileName || 'downloaded_file';

        // 触发下载
        link.click();

        // 释放内存
        URL.revokeObjectURL(downloadUrl);

        ElMessage.success('文件下载成功！');
      } else {
        ElMessage.error('文件下载失败！');
      }
    })
    .catch(error => {
      if (error.name === 'AbortError') {
        console.log('下载已取消');
      } else {
        console.error('下载文件时出错：', error);
        ElMessage.error('文件下载失败！');
      }
    })
    .finally(() => {
      loading.close(); // 确保关闭加载提示框
    });
};


  

// 分享
const shareRef = ref();
const share = (row) => {
  shareRef.value.show(row);
};
</script>



<style lang="scss">
@import "@/assets/file.list.scss";

.file-item {
  display: flex;
  align-items: center;
}
.editing-input {
  background-color: #1390d3;
  color: #000;
}

.editing-input:focus {
    background-color: #1390d3; /* 在输入框聚焦时改变底色 */
    
}
.action-icons {
  display: none;
  margin-left: 10px;
}

.file-item:hover .action-icons {
  display: flex;
}

.action-icons el-button {
  margin-right: 5px;
}

/* 容器样式 */
.action-container {
  display: flex;
  justify-content: center;
  margin-top: 15px; /* 与进度条的间距 */
}

/* 按钮样式 */
.cancel-button1 {
  padding: 8px 20px !important;
  font-size: 14px;
  font-weight: 500;
  color: #fff;
  background-color: #f56c6c;
  border: 1px solid #f56c6c;
  border-radius: 20px; /* 圆润的边框 */
  cursor: pointer;
  transition: all 0.3s ease; /* 添加平滑过渡效果 */
  outline: none;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 添加轻微阴影 */
}

.cancel-button1:hover {
  background-color: #ff7b7b; /* 鼠标悬停时背景颜色 */
  border-color: #ff7b7b; /* 悬停时边框颜色 */
}

.cancel-button1:active {
  background-color: #d9534f; /* 按下时背景颜色 */
  border-color: #d9534f; /* 按下时边框颜色 */
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15); /* 按下时内部阴影 */
}
</style>
